﻿using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web.SessionState;
using NUnit.Framework;

namespace Mirabeau.Web.Session.UnitTests
{
    /// <summary>
    /// Tests for the serializable collection.
    /// </summary>
    [TestFixture]
    public class SerializableSessionStateItemCollectionTest
    {
        /// <summary>
        /// Dirty must be set to false after initialization
        /// </summary>
        [Test]
        public void DirtyMustBeFalseAfterInitialization()
        {
            // act
            SerializableSessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            
            Assert.That(collection.Dirty, Is.False);
        }

        /// <summary>
        /// Dirty the index of the must be true after add by the named indexer.
        /// </summary>
        [Test]
        public void DirtyMustBeTrueAfterAddByIndex()
        {
            ISessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            
            // act
            collection["test"] = 1;

            Assert.That(collection.Dirty,Is.True);
        }

        /// <summary>
        /// Dirty the index of the must be true after add by the integer index.
        /// </summary>
        [Test]
        public void DirtyMustBeTrueAfterAddByIntegerIndex()
        {
            ISessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            collection["a"] = 1;
            collection.Dirty = false;
            
            // act
            collection[0] = 2;
                        
            Assert.That(collection.Dirty, Is.True);
        }

        /// <summary>
        /// Dirty the must be true after clear.
        /// </summary>
        [Test]
        public void DirtyMustBeTrueAfterClear()
        {
            ISessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            
            // act
            collection.Clear();

            Assert.That(collection.Dirty, Is.True);   
        }

        /// <summary>
        /// Dirty the must be true after remove.
        /// </summary>
        [Test]
        public void DirtyMustBeTrueAfterRemove()
        {
            ISessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            collection["test"] = 1;
            
            // act
            collection.Remove("test");

            Assert.That(collection.Dirty, Is.True);
        }

        /// <summary>
        /// Dirty the must be true after remove at.
        /// </summary>
        [Test]
        public void DirtyMustBeTrueAfterRemoveAt()
        {
            ISessionStateItemCollection collection = new SerializableSessionStateItemCollection();
            collection["a"] = 1;
            collection.Dirty = false;
            
            // act
            collection.RemoveAt(0);

            Assert.That(collection.Dirty, Is.True);
        }
        
        /// <summary>
        /// Collection must be serializable.
        /// </summary>
        [Test]
        public void CollectionMustBeSerializable()
        {
            ISessionStateItemCollection serializableCollection = new SerializableSessionStateItemCollection();
            
            // act
            byte[] serializedCollectionData = Serialize(serializableCollection);

            Assert.That(serializedCollectionData, Has.Length.GreaterThan(0));
        }

        /// <summary>
        /// Collection must deserialize correctly.
        /// </summary>
        [Test]
        public void CollectionMustDeserializeCorrectly()
        {
            ISessionStateItemCollection serializableCollection = new SerializableSessionStateItemCollection();
            serializableCollection["testItem"] = "testValue1";
            byte[] serializedCollectionData = Serialize(serializableCollection);

            // act
            ISessionStateItemCollection deserializedCollection = Deserialize<SerializableSessionStateItemCollection>(serializedCollectionData);
            
            Assert.That(deserializedCollection, Has.Count.EqualTo(1));
            Assert.That(deserializedCollection["testItem"], Is.EqualTo("testValue1"));
        }

        /// <summary>
        /// Deserializes the specified serialized collection data.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="serializedCollectionData">The serialized collection data.</param>
        /// <returns></returns>
        public static T Deserialize<T>(byte[] serializedCollectionData)
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                stream.Write(serializedCollectionData, 0, serializedCollectionData.Length);
                stream.Seek(0, SeekOrigin.Begin);
                return (T) binaryFormatter.Deserialize(stream);
            }
        }

        /// <summary>
        /// Serializes the specified object.
        /// </summary>
        /// <param name="serializableCollection">The serializable object.</param>
        /// <returns></returns>
        public static byte[] Serialize(object serializableCollection)
        {
            BinaryFormatter serializer = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {                
                serializer.Serialize(stream, serializableCollection);
                return stream.ToArray();
            }
        }
    }
}
